#define _MULTI_THREADED
#include <pthread.h>
#include <stdio.h>      /* for printf() and fprintf() */
#include <sys/socket.h> /* for socket(), connect(), send(), and recv() */
#include <arpa/inet.h>  /* for sockaddr_in and inet_addr() */
#include <stdlib.h>     /* for atoi() and exit() */
#include <string.h>     /* for memset() */
#include <unistd.h>     /* for close() */
#include <fstream>
#include <iostream>
#include <linux/tcp.h>
#include <linux/ip.h>
#include <sys/stat.h>
#include "ntcp.h"


using namespace std;


long 
get_file_size( char * filename ) 
{ 	           
	struct stat f_stat; 

	if( stat( filename, &f_stat ) == -1 ){ 
		return -1; 
									           
	} 
					         
	return (long)f_stat.st_size; 								       
}

int main(int argc, char *argv[])
{
		int ctrlSock;
		struct ntcp_sock sock;            
    	struct sockaddr_in servAddr; 
		struct sockaddr_in transAddr;
    	unsigned short ctrlPort;         /* port for control link */
    	char *servIP;                    /* Server IP address (dotted quad) */
		char *srcIP;
		
    	//servIP = "127.0.0.1";
    	servIP ="192.168.10.113";
		srcIP = "192.168.20.71";
   		// servIP = "59.66.36.113";             /* First arg: server IP address (dotted quad) */
    	ctrlPort = 1010;  /* 7 is the well-known port for the echo service */
		int dataLinkPort = 1000;
		int srcPort = 1001;

		/* Construct the server address structure */
   	 	memset(&servAddr, 0, sizeof(servAddr));     /* Zero out structure */
   	    servAddr.sin_family      = AF_INET;             /* Internet address family */
  	  	servAddr.sin_addr.s_addr = inet_addr(servIP);   /* Server IP address */
 	   	servAddr.sin_port        = htons(ctrlPort); /* Server port */
		
		if ((ctrlSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))<0){
			DieWithError("control socket() failed");
		}else{
			printf("control socket establised!\n");
		}
		
		if (connect(ctrlSock, (struct sockaddr*)&servAddr,	sizeof(servAddr))< 0){
			DieWithError("connet control socket failed!");
		}else{
			printf("socket connected to server %s:%d \n", servIP, ctrlPort);
		}
		
		char fileName[] = "input.mkv";
		printf("send file name: %s\n", fileName);
    	
		long fileSize = get_file_size(fileName);	
		char dataSize[32] = "FILESIZE ";
		sprintf(&dataSize[9],"%d",fileSize);
		printf("send file size: %s\n",dataSize);
		int msgLen = strlen(dataSize);  
		int bytesRcvd = 0;
		fd_set fdsr;
		int maxsock = ctrlSock;
		struct timeval tv;
		int ret = 0;
		
		char echoBuffer[RCVBUFSIZE];
		memset(echoBuffer,0,RCVBUFSIZE);
			
		if (send(ctrlSock, dataSize, msgLen, 0) != msgLen)
		    DieWithError("send() sent a different number of bytes than expected");

/*		for(;;){	
		    FD_ZERO(&fdsr);
		    FD_SET(ctrlSock, &fdsr);
		    tv.tv_sec = 1;
		    tv.tv_usec = 0;

		    ret = select(maxsock + 1, &fdsr, NULL, NULL, &tv);
		    if(ret < 0){
				DieWithError("ntcp_thread_recv() select failed");
		    }else if(ret == 0){
				continue;
		    }

		    if ((bytesRcvd = recv(ctrlSock, echoBuffer, RCVBUFSIZE, 0)) <= 0){
				DieWithError("recv begin error\n");
		    }
		    	printf("recv %s\n",echoBuffer);
		    if(strstr(echoBuffer, "BEGIN") != NULL){
				break;
		    }
		    DieWithError("begin fails");
		}	 
*/		
		
		memset(&transAddr, 0, sizeof(transAddr));     /* Zero out structure */
   	    transAddr.sin_family      = AF_INET;             /* Internet address family */
  	  	transAddr.sin_addr.s_addr = inet_addr(servIP);   /* Server IP address */
 	   	transAddr.sin_port        = htons(dataLinkPort); /* Server port */

   		if (ntcp_create_sock(&sock,ctrlSock, &transAddr, srcPort, dataLinkPort) < 0)
        	DieWithError("socket() failed");
    	else{
    		printf(" data socket established!\n");
    	}
		
		FILE *fp;
   		
     	if((fp=fopen(fileName,"rb")) == NULL){
     		DieWithError("open input file failed!");
     	}

		char sendBuffer[SENDBUFSIZE];
		memset(sendBuffer, 0,SENDBUFSIZE);
	
		int start = time(NULL);

		int sendSize = 0;
		long transSize = 0;
		while((sendSize = fread(sendBuffer,1,SENDBUFSIZE-1,fp)) > 0)	
		{
			transSize += sendSize;

			ntcp_sendto(&sock,sendBuffer,sendSize,0,(struct sockaddr*)&transAddr,sizeof(transAddr));
			memset(sendBuffer, 0 , SENDBUFSIZE);
		};
	
		fclose(fp);
		ntcp_close(&sock);
		
		//printf("transfer total size: %d time %d s\n",transSize, (time(NULL)-start));
    
		exit(0);
}
